#include "stdlib.hpp"
#include <purewell/types.hpp>
#include <purewell/socket.hpp>

namespace purewell
{

PWSocket::PWSocket()
{
}

PWSocket::~PWSocket()
{
}

bool
PWSocket::initialize(const char* name, int omode, int perm)
{
	_PWTRACE("%s","DO NOT USE THIS FUNCTION");
	abort();
	return false;
}

PWSocketAddress&
PWSocket::getPeerName(PWSocketAddress& addr) const
{
	addr.clear();
	struct sockaddr_storage sa;
	socklen_t slen(sizeof(sa));
	memset(&sa, 0x00, sizeof(sa));

	if ( 0 == getpeername(m_fd, (struct sockaddr*)&sa, &slen) )
	{
		addr.assign((struct sockaddr*)&sa, slen);
	}

	return addr;
}

PWSocketAddress&
PWSocket::getSocketName(PWSocketAddress& addr) const
{
	addr.clear();
	struct sockaddr_storage sa;
	socklen_t slen(sizeof(sa));
	memset(&sa, 0x00, sizeof(sa));

	if ( 0 == getsockname(m_fd, (struct sockaddr*)&sa, &slen) )
	{
		addr.assign((struct sockaddr*)&sa, slen);
	}

	return addr;
}

bool
PWSocket::initialize(int family, int socktype, int protocol)
{
	const int fd(socket(family,socktype,protocol));

	if ( -1 == fd ) return false;
	if ( attach(fd) ) return true;

	::close(fd);
	return false;
}

bool
PWSocket::shutdown(int type)
{
	return 0 == ::shutdown(m_fd, type);
}

bool
PWSocket::bind(const PWSocketAddress& addr)
{
	return 0 == ::bind(m_fd,
		(struct sockaddr*)addr.getAddress(), addr.getSize());
}

bool
PWSocket::listen(size_t backlog)
{
	return 0 == ::listen(m_fd, backlog);
}

bool
PWSocket::accept(PWSocket* sock) const
{
	if ( !sock ) return false;
	const int newfd(::accept(m_fd,NULL,NULL));
	if ( -1 == newfd ) return false;

	if ( !sock->attach(newfd) )
	{
		::close(newfd);
		return false;
	}

	return true;
}

bool
PWSocket::connect(const PWSocketAddress& addr)
{
	return 0 == ::connect(m_fd,
		(struct sockaddr*)addr.getAddress(), addr.getSize());
}

ssize_t
PWSocket::receive(void* buf, size_t blen, int flag)
{
	return ::recv(m_fd, (char*)buf, blen, flag);
}

ssize_t
PWSocket::receiveFrom(void* buf, size_t blen, int flag,
	PWSocketAddress* paddr)
{
	char sa[PWSA_MAX_LEN];
	socklen_t slen(PWSA_MAX_LEN);
	const ssize_t res( ::recvfrom(m_fd, (char*)buf, blen, flag,
		(struct sockaddr*)sa, &slen) );
	if ( NULL != paddr && res >= 0 )
	{
		paddr->assign(sa, slen);
	}

	return res;
}

ssize_t
PWSocket::send(const void* buf, size_t blen, int flag)
{
	return ::send(m_fd, (const char*)buf, blen, flag);
}

ssize_t
PWSocket::sendTo(const void* buf, size_t blen, int flag,
	const PWSocketAddress* paddr)
{
	return ( ::sendto(m_fd, (const char*)buf, blen, flag,
		(struct sockaddr*)paddr->getAddress(),
		paddr->getSize()) );
}

ssize_t
PWSocket::read(void* buf, size_t blen)
{
	return ::recv(m_fd,(char*)buf,blen,0);
}

ssize_t
PWSocket::write(const void* buf, size_t blen)
{
	return ::send(m_fd,(const char*)buf,blen,0);
}


};//namespace purewell

